package cn.dengta.webapp.trade.entity;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.Map;

import cn.dengta.common.model.*;
import cn.dengta.context.model.LabelI18nProxy;
import cn.dengta.context.model.Member;
import cn.dengta.webapp.base.entity.BizEntity;
import cn.dengta.webapp.trade.model.AgentLevel;
import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import me.codeplayer.util.*;
import org.apache.commons.lang3.BooleanUtils;

import static cn.dengta.context.model.AdminEnumI18nKey.*;

/**
 * 代理商
 */
@Setter
@Getter
@Accessors(chain = true)
@TableName("dt_agent")
public class Agent extends BizEntity implements BizFlag.WritableBizFlag {

	// bizFlag
	/** 是否发放补贴 */
	public final static long FLAG_SEND_SUPPLY = 1L;
	/** 是否流水打包 */
	public final static long FLAG_PACK_BILL = 1L << 1;
	/** 标识：是否标记钻石收费 */
	public static final long FLAG_MARK_PAY_COIN = 1L << 2;
	/** 标识：是否倾向支付 */
	public static final long FLAG_BIASED_PAY = 1L << 3;
	// liveFlag
	/** 标识：lvl */
	public static final long FLAG_CHAT = 1L;
	/** 标识：直播 */
	public static final long FLAG_LIVE = 1L << 1;

	/** 推广员ID */
	private Long userId;
	/** 推广员名 */
	private String name;
	/** 父类ID */
	private Long parentId;
	/** 类型：0=内部代理商;1=外部代理商 */
	private AgentType type;
	/** 级别：1=一级推广员；2=二级推广员 */
	private AgentLevel level;
	/** 加盟时间 */
	private Date joinTime;
	/** 签约到期时间 */
	private Date signExpireTime;
	/** 邀请码 */
	private String inviteCode;
	/** 主播的分成比例（0-100）% */
	private Integer anchorRate;
	/** 主播的直播分成比例（0-100）% */
	private Integer anchorLiveRate;
	/** 招商专员ID */
	private Long inviteEmpId;
	/** 备注 */
	private String remark;
	/** 代理商姓名 */
	public String realName;
	/** 代理商手机号码 */
	public String phone;
	/** 代理商身份证号 */
	public String certNo;
	/** 业务标识 */
	private long bizFlag;
	/** 代理商详情ID */
	private Long agentInfoId;
	/** 奖励模板ID */
	private Long agentAwardConfigId;
	/** 直播奖励模板ID */
	private Long agentAwardConfigLiveId;
	/** 用户的分成比例（0-100）% ，仅限内部推广员 */
	private Integer userRate;
	/** 保证金（元） */
	private BigDecimal bondMoney;
	/** 审核人 */
	protected Long verifyUserId;
	/** 审核备注 */
	protected String verifyRemark;
	/** 审核时间 */
	protected Date verifyTime;
	/** 类型业务标识：1v1，直播 */
	private long liveFlag;
	/** 添加的代理人Id */
	private Long addEmpId;

	/** 代理人 */
	private Long belongId;

	public transient Integer sendSupply, packBill, payCoin, biasedPay;
	public transient Integer chatOpen, liveOpen;

	public Agent init(Agent input, Date now) {
		this.userId = X.expectNotNull(userId, input.userId);
		this.name = X.expectNotNull(input.name, name);
		this.parentId = X.expectNotNull(parentId, input.parentId);
		this.type = X.expectNotNull(type, input.type);
		this.level = X.expectNotNull(level, input.level);
		this.signExpireTime = X.expectNotNull(input.signExpireTime, signExpireTime);
		this.joinTime = X.expectNotNull(input.joinTime, joinTime);
		this.inviteCode = X.expectNotNull(inviteCode, input.inviteCode);
		this.anchorRate = X.expectNotNull(input.anchorRate, anchorRate);
		this.anchorLiveRate = X.expectNotNull(input.anchorLiveRate, anchorLiveRate);
		this.inviteEmpId = X.expectNotNull(input.inviteEmpId, inviteEmpId);
		this.agentAwardConfigId = X.expectNotNull(input.agentAwardConfigId, agentAwardConfigId);
		this.agentAwardConfigLiveId = X.expectNotNull(input.agentAwardConfigLiveId, agentAwardConfigLiveId);
		this.userRate = X.expectNotNull(userRate, 100);
		this.remark = StringUtil.toString(input.remark);
		this.realName = X.expectNotNull(input.realName, realName);
		this.bondMoney = X.expectNotNull(input.bondMoney, bondMoney);
		this.phone = X.expectNotNull(input.phone, phone);
		this.certNo = X.expectNotNull(input.certNo, certNo);
		this.addEmpId = X.expectNotNull(input.addEmpId, addEmpId);
		this.sendSupply = X.expectNotNull(input.sendSupply, BooleanUtils.toInteger(hasFlag(FLAG_SEND_SUPPLY)));
		this.packBill = X.expectNotNull(input.packBill, BooleanUtils.toInteger(hasFlag(FLAG_PACK_BILL)));
		this.payCoin = X.expectNotNull(input.payCoin, BooleanUtils.toInteger(hasFlag(FLAG_MARK_PAY_COIN)));
		this.biasedPay = X.expectNotNull(input.biasedPay, BooleanUtils.toInteger(hasFlag(FLAG_BIASED_PAY)));
		this.chatOpen = X.expectNotNull(input.chatOpen, BooleanUtils.toInteger(BizFlag.hasFlag(liveFlag, FLAG_CHAT)));
		this.liveOpen = X.expectNotNull(input.liveOpen, BooleanUtils.toInteger(BizFlag.hasFlag(liveFlag, FLAG_LIVE)));
		this.verifyRemark = StringUtil.toString(verifyRemark);
		toggleBizFlag();
		super.init(input.status, input.state);
		super.initTime(now);
		return this;
	}

	private void toggleBizFlag() {
		toggleFlag(FLAG_SEND_SUPPLY, Status.asResult(this.sendSupply));
		toggleFlag(FLAG_PACK_BILL, Status.asResult(this.packBill));
		toggleFlag(FLAG_MARK_PAY_COIN, Status.asResult(this.payCoin));
		toggleFlag(FLAG_BIASED_PAY, Status.asResult(this.biasedPay));
		this.liveFlag = BizFlag.WritableBizFlag.toggleFlag(liveFlag, FLAG_CHAT, Status.asResult(this.chatOpen));
		this.liveFlag = BizFlag.WritableBizFlag.toggleFlag(liveFlag, FLAG_LIVE, Status.asResult(this.liveOpen));
	}

	/** 1v1类型 */
	public boolean hasChatFlag() {
		return BizFlag.hasFlag(liveFlag, FLAG_CHAT);
	}

	/** 直播类型 */
	public boolean hasLiveFlag() {
		return BizFlag.hasFlag(liveFlag, FLAG_LIVE);
	}

	public boolean isOpen() {
		return AgentStatus.VALID.eq(status);
	}

	/** 主播分成 * 用户分成 */
	public BigDecimal calcAgentRate(BigDecimal rate, boolean live) {
		return new Arith(rate != null ? rate.multiply(Arith.HUNDRED) : (live ? anchorLiveRate : anchorRate)).multiply(userRate).divide(Arith.MYRIAD).setScale(3, RoundingMode.FLOOR).toBigDecimal();
	}

	/** 主播分成 * 用户抽成 = 推广员抽成 */
	public BigDecimal calcUserRate(BigDecimal rate, boolean live) {
		int remainRate = 100 - userRate;
		return remainRate > 0 ? new Arith(rate != null ? rate.multiply(Arith.HUNDRED) : (live ? anchorLiveRate : anchorRate)).multiply(remainRate).divide(Arith.MYRIAD).setScale(3, RoundingMode.FLOOR).toBigDecimal() : BigDecimal.ZERO;
	}

	/** 外部推广员类型 */
	@JSONField(serialize = false)
	public boolean isOuter() {
		return AgentType.OUTER == type;
	}

	/** 内部推广员类型 */
	@JSONField(serialize = false)
	public boolean isInner() {
		return AgentType.INNER == type;
	}

	/** 外部是否可编辑 */
	public boolean canEdit() {
		return isOuter() && isTwo() && AgentStatus.of(status).canEdit;
	}

	public boolean needPayCoin() {
		return hasFlag(FLAG_MARK_PAY_COIN);
	}

	public boolean forBiasedPay() {
		return hasFlag(FLAG_BIASED_PAY);
	}

	/** 一级推广员 */
	@JSONField(serialize = false)
	public boolean isOne() {
		return level == AgentLevel.ONE;
	}

	/** 二级推广员 */
	@JSONField(serialize = false)
	public boolean isTwo() {
		return level == AgentLevel.TWO;
	}

	@JSONField(serialize = false)
	public String getName_(boolean showUserId) {
		final String name = isOuter() ? this.name + level.getSign() : this.name;
		return showUserId && userId != null ? "【" + Member.encode(userId) + "】" + name : name;
	}

	@JSONField(serialize = false)
	public String getName_() {
		return getName_(false);
	}

	public static Map<String, Object> asEmbedInfo(Agent source) {
		return asEmbed(source, t -> CollectionUtil.ofHashMap("id", t.getId(), "name", t.getName(), "type_", t.getType().getLabel(), "level_", X.map(t.getLevel(), AgentLevel::getLabel), "level", t.getLevel()));
	}

	public static Map<String, Object> asEmbed(Agent source) {
		return asEmbed(source, t -> CollectionUtil.ofHashMap("id", t.getId(), "name", t.getName_()));
	}

	@Override
	public void setId(Long id) {
		this.id = id;
	}

	public void setUserId(Long userId) {
		this.userId = userId;
	}

	@Override
	public void setBizFlag(long flag) {
		this.bizFlag = flag;
	}

	@Getter
	public enum AgentType implements LabelI18nProxy<AgentType, Integer> {
		/** 内部代理商 */
		INNER(0, AGENT_TYPE_INNER),
		/** 外部代理商 */
		OUTER(1, AGENT_TYPE_OUTER);

		final ValueProxy<AgentType, Integer> proxy;

		// 构造函数，枚举类型只能为私有
		AgentType(Integer value, String label) {
			this.proxy = new ValueProxy<>(this, value, label);
		}

		public boolean isInner() {
			return this == INNER;
		}

		public static final AgentType[] CACHE = values();

		public static AgentType of(Integer value) {
			return INNER.getValueOf(value);
		}

	}

	@Getter
	public enum AgentStatus implements LabelI18nProxy<AgentStatus, Integer> {
		/** 已注销 */
		INVALID(-99, AGENT_STATUS_INVALID, false),
		/** 审核不通过 */
		VERIFY_FALSE(-1, AGENT_STATUS_VERIFY_FALSE, true),
		/** 待审核 */
		WAIT_VERIFY(0, AGENT_STATUS_WAIT_VERIFY, true),
		/** 启用 */
		VALID(1, AGENT_STATUS_VALID, false),
		//
		;

		public final Integer value;
		public final boolean canEdit;
		public final ValueProxy<AgentStatus, Integer> proxy;

		AgentStatus(Integer value, String label, boolean canEdit) {
			this.value = value;
			this.canEdit = canEdit;
			this.proxy = new ValueProxy<>(this, value, label);
		}

		public static AgentStatus[] getValues() {
			return ValueProxy.getCachedArray(AgentStatus.class, AgentStatus::values);
		}

		public static AgentStatus of(Integer value) {
			return WAIT_VERIFY.getValueOf(value);
		}

	}

	public static final String USER_ID = "user_id";
	public static final String NAME = "name";
	public static final String PARENT_ID = "parent_id";
	public static final String TYPE = "type";
	public static final String LEVEL = "level";
	public static final String SIGN_EXPIRE_TIME = "sign_expire_time";
	public static final String INVITE_CODE = "invite_code";
	public static final String ANCHOR_RATE = "anchor_rate";
	public static final String INVITE_EMP_ID = "invite_emp_id";
	public static final String REMARK = "remark";
	public static final String BIZ_FLAGS = "biz_flags";
	public static final String BELONG_ID = "belong_id";
	public static final String ADD_EMP_ID = "add_emp_id";

}
